#include <iostream>
#include <string>
#include <cerrno>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

const std ::string g_pathname = "/home/oo_zz/2024-8-9/shm";
const int g_proj_id = 0x66;
const int size = 4096;
enum player
{
    serve,
    client
};

class shm
{
private:
    int create_shm(key_t key, int who)
    {
        if (who == client)
        {
            return shmget(key, size, IPC_CREAT | 0666);
        }
        else
        {
            return shmget(key, size, IPC_CREAT | IPC_EXCL | 0666);
        }
    }

    std::string to_hex(int key)
    {
        char buffer[128] = {0};
        int n = sprintf(buffer, "%x", key);
        buffer[n] = 0;

        return std::string(buffer);
    }

public:
    shm(int who, const std::string pathname, const int proj_id)
        : _who(who), _pathname(pathname), _proj_id(proj_id)
    {
        key_t key = ftok(_pathname.c_str(), _proj_id);
        int shmid = create_shm(key, _who);
        if (shmid < 0)
        {
            perror("shm(){} : ");
            exit(1);
        }
        _shmid = shmid;

        std::cout << "create successfully, shmid: " << _shmid << ", key: " << to_hex(key) << ", who: " << _who << std::endl;

        attach_shm();
    }
    ~shm()
    {
        if (_who == client && shmctl(_shmid, IPC_RMID, nullptr))
        {
            perror("shmctl: ");
            exit(1);
        }
        std::cout << "delete successfully" << std::endl;

        detach(nullptr);
    }
    void *attach_shm()
    {
        void *shmaddr = shmat(_shmid, nullptr, 0);
        _shmaddr = (char *)shmaddr;
        if (shmaddr == nullptr)
            perror("shamt: ");
        std::cout << to_string(_who) << " attach successfully" << std::endl;
        return shmaddr;
    }
    void detach(void *shmaddr)
    {
        if (shmaddr == nullptr)
            return;
        std::cout << to_string(_who) << " detach successfully" << std::endl;
        shmdt(_shmaddr);
    }
    std::string to_string(int key)
    {
        if (key == client)
            return "client";
        else if (key == serve)
            return "serve";
        else
            return "none";
    }
    char* addr()
    {
        return _shmaddr;
    }

private:
    int _who;
    const std::string _pathname;
    const int _proj_id;
    int _shmid;
    char *_shmaddr;
};
